/*******************************************************************************
 * Copyright (c) 2005, 2014 springside.github.io
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 *******************************************************************************/
package com.whxd.smarthome.api.rest;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.validation.Validator;

import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hsview.client.HsviewClient;
import com.hsview.client.HsviewResponse;
import com.hsview.client.api.civil.device.BindDevice;
import com.hsview.client.api.civil.device.DeleteDeviceShare;
import com.hsview.client.api.civil.device.SetDeviceShare;
import com.hsview.client.api.civil.device.SetDeviceShare.RequestData.ShareInfosElement;
import com.hsview.client.api.civil.device.UnbindDevice;
import com.hsview.client.api.civil.open.GetDevices;
import com.hsview.client.api.civil.open.GetRealplayUrl;
import com.whxd.framework.common.dto.ReturnObject;
import com.whxd.framework.security.SecurityUtils;
import com.whxd.framework.utils.StringUtil;
import com.whxd.smarthome.Config;
import com.whxd.smarthome.api.rest.dto.BindDeviceRequestDto;
import com.whxd.smarthome.api.rest.dto.ChannelDto;
import com.whxd.smarthome.api.rest.dto.GetDeviceChannelsRequestDto;
import com.whxd.smarthome.api.rest.dto.GetDeviceChannelsResponseDto;
import com.whxd.smarthome.api.rest.dto.GetDevicesRequestDto;
import com.whxd.smarthome.api.rest.dto.GetDevicesResponseDto;
import com.whxd.smarthome.api.rest.dto.GetRealplayUrlRequestDto;
import com.whxd.smarthome.api.rest.dto.GetRealplayUrlResponseDto;
import com.whxd.smarthome.api.rest.dto.ShareDeviceRequestDto;
import com.whxd.smarthome.api.rest.dto.UnbindDeviceRequestDto;
import com.whxd.smarthome.api.rest.dto.UpdateDeviceRequestDto;
import com.whxd.smarthome.api.v1.dh.ws.dto.GetDevicesDto;
import com.whxd.smarthome.core.entity.DhDevice;
import com.whxd.smarthome.core.entity.DhDeviceChannel;
import com.whxd.smarthome.core.entity.DhDeviceShare;
import com.whxd.smarthome.core.service.DhDeviceChannelService;
import com.whxd.smarthome.core.service.DhDeviceService;
import com.whxd.smarthome.core.service.DhDeviceShareService;
import com.whxd.smarthome.util.MediaTypes;

/**
 * 设备管理的Restful API的Controller.
 * 
 * @author 张世鹏
 *
 */
@RestController
@RequestMapping(value = "/api/v1/dh/device")
public class DhDeviceRestController {

	private Logger logger = LoggerFactory.getLogger(DhDeviceRestController.class);
	private ObjectMapper mapper = new ObjectMapper();
	
	@Autowired
	private DhDeviceService dhDeviceService;
	@Autowired
	private DhDeviceShareService dhDeviceShareService;
	@Autowired
	private DhDeviceChannelService dhDeviceChannelService;
	@Autowired
	private Validator validator;

	@RequestMapping(value = "/getDevices", method = RequestMethod.POST, produces = MediaTypes.JSON_UTF_8)
	@ResponseBody
	public ReturnObject getDevices(@RequestBody GetDevicesDto dto) {
		try {
			logger.info("GetDevices request data:" + mapper.writeValueAsString(dto));
		} catch (JsonProcessingException e) {
			logger.warn(e.getMessage());
		}

		HsviewClient m_client = new HsviewClient();
		m_client.setHost(Config.host);
		m_client.setAuth(Config.devUser, Config.devPassword); // �û���// ����

		GetDevices req = new GetDevices();
		req.data.accessToken = dto.getAccessToken();

		GetDevices.Response resp = (GetDevices.Response) m_client.request(req, 30000);

		if (resp == null) {
			logger.error("调用GetDevices接口时发生未知发错");
			return new ReturnObject(false, "发生未知发错");
		}

		logger.info("GetDevices response data:" + resp.getBody());

		ReturnObject ro = new ReturnObject();
		if (resp.getCode() == HttpStatus.SC_OK) {
			if (resp.getApiRetCode() == HsviewResponse.API_SUCCESS) {

				ro.setSuccess(true);
				ro.setMsg("[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());

				List<GetDevicesResponseDto> result = new ArrayList<GetDevicesResponseDto>();
				//List<DhDeviceChannel> dhDeviceChannels = null;//TODO wwp ADD
				for (GetDevices.ResponseData.DevicesElement element : resp.data.devices) {
					GetDevicesResponseDto deviceDto = new GetDevicesResponseDto();
					deviceDto.setBeSharedFrom(element.beSharedFrom);
					deviceDto.setBeSharedTo(element.beSharedTo);
					deviceDto.setDeviceId(element.deviceId);
					deviceDto.setDeviceModel(element.deviceModel);
					deviceDto.setName(element.name);
					deviceDto.setOnline(element.online);
					
					for (GetDevices.ResponseData.DevicesElement.ChannelsElement channelElement : element.channels) {
						//dhDeviceChannels = new ArrayList<DhDeviceChannel>();
						ChannelDto channelDto = new ChannelDto();
						channelDto.setChannelId(channelElement.channelId);
						channelDto.setChannelName(channelElement.channelName);
						channelDto.setChannelOnline(channelElement.channelOnline);
						channelDto.setChannelPicUrl(channelElement.channelPicUrl);
						
						//dhDeviceChannels.add(new DhDeviceChannel(element.deviceId, channelDto));
						deviceDto.getChannels().add(channelDto);
					}
					
					result.add(deviceDto);
				}

				//TODO 刷新设备信息并过滤
				result = dhDeviceService.flushAndFilterDevice(result);
				
				ro.setObj(result);
				
				//dhDeviceChannelService.saveDeviceChannel(dhDeviceChannels);
			} else {
				ro.setSuccess(false);
				ro.setMsg("[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());
				logger.warn("[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());
			}
		} else {
			ro.setSuccess(false);
			ro.setMsg("[" + resp.getCode() + "] " + resp.getDesc());
			logger.error("[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());
		}

		return ro;
	}
	

	@RequestMapping(value = "/getRealplayUrl", method = RequestMethod.POST, produces = MediaTypes.JSON_UTF_8)
	@ResponseBody
	public ReturnObject getRealplayUrl(@RequestBody GetRealplayUrlRequestDto dto) {
		try {
			logger.info("GetRealplayUrl data:" + mapper.writeValueAsString(dto));
		} catch (JsonProcessingException e) {
			logger.warn(e.getMessage());
		}

		HsviewClient m_client = new HsviewClient();
		m_client.setHost(Config.host);
		m_client.setAuth(Config.devUser, Config.devPassword); // �û���// ����

		GetRealplayUrl req = new GetRealplayUrl();
		req.data.accessToken = dto.getAccessToken();
		req.data.channelId = dto.getChannelId();
		req.data.deviceId = dto.getDeviceId();
		req.data.streamId = dto.getStreamId();

		GetRealplayUrl.Response resp = (GetRealplayUrl.Response) m_client.request(req, 30000);

		if (resp == null) {
			logger.error("调用GetRealplayUrl接口时发生未知发错");
			return new ReturnObject(false, "发生未知发错");
		}

		logger.info("GetRealplayUrl response data:" + resp.getBody());

		ReturnObject ro = new ReturnObject();
		if (resp.getCode() == HttpStatus.SC_OK) {
			if (resp.getApiRetCode() == HsviewResponse.API_SUCCESS) {

				ro.setSuccess(true);
				ro.setMsg("[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());

				GetRealplayUrlResponseDto result = new GetRealplayUrlResponseDto();
				result.setResource(resp.data.resource);

				ro.setObj(result);

			} else {
				ro.setSuccess(false);
				ro.setMsg("[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());
				logger.warn("[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());
			}
		} else {
			ro.setSuccess(false);
			ro.setMsg("[" + resp.getCode() + "] " + resp.getDesc());
			logger.error("[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());
		}

		return ro;
	}

	@RequestMapping(value = "/bindDevice", method = RequestMethod.POST, produces = MediaTypes.JSON_UTF_8)
	@ResponseBody
	public ReturnObject bindDevice(@RequestBody BindDeviceRequestDto dto) {
		logger.info("BindDevice data:" + dto);

		HsviewClient m_client = new HsviewClient();
		m_client.setHost(Config.host);
		m_client.setAuth(Config.devUser, Config.devPassword);

		BindDevice req = new BindDevice();
		req.data.deviceId = dto.getDeviceId();

		BindDevice.Response resp = (BindDevice.Response) m_client.request(req, 30000);

		if (resp == null) {
			logger.error("调用BindDevice接口时发生未知发错");
			return new ReturnObject(false, "发生未知发错");
		}

		logger.info("BindDevice response data:" + resp.getBody());

		if (resp.getCode() == HttpStatus.SC_OK) {
			if (resp.getApiRetCode() == HsviewResponse.API_SUCCESS) {
				//TODO 保存设备到本地
				saveDevice(dto);
				
				return _realBindDevice(dto);
			} else {
				logger.warn("[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());
				return new ReturnObject(false, "[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());
			}
		} else {
			logger.error("[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());
			return new ReturnObject(false, "[" + resp.getCode() + "] " + resp.getDesc());
		}

	}
	
	
	
	//TODO 绑定设备到大华时，在自己本地数据库保存该设备的拥有者 
	private void saveDevice(BindDeviceRequestDto dto) {
		DhDevice device = new DhDevice();
		device.setCreateDt(StringUtil.getCuttentTime("yyyy-MM-dd HH:mm:ss"));
		device.setDeviceId(dto.getDeviceId());
		device.setIsLock("N");
		device.setDeviceType("shexiangtou");
		device.setOwnerUsername(SecurityUtils.getCurrentSecurityUser().getUsername());
		device.setOwnerMobile(SecurityUtils.getCurrentSecurityUser().getMobile());
		//update by kevin.liu 2015-05-28 添加默认设备名
		device.setDeviceName(dto.getDeviceId());
		device.setBeSharedFrom(false);
		device.setBeSharedTo(false);
		//device Service 
		dhDeviceService.saveDevice(device);
	}
	
	
	
	
	

	private ReturnObject _realBindDevice(BindDeviceRequestDto dto) {
		logger.info("SetDeviceShare data:" + dto);

		HsviewClient m_client2 = new HsviewClient();
		m_client2.setHost(Config.host);
		m_client2.setAuth(Config.devUser, Config.devPassword);

		SetDeviceShare req2 = new SetDeviceShare();
		req2.data.deviceId = dto.getDeviceId();
		req2.data.channelId = "0";

		ShareInfosElement element = new ShareInfosElement();
		element.username = SecurityUtils.getCurrentSecurityUser().getUsername();
		element.functions = "videoMonitor";
		element.activeTime = new Date().getTime()/1000;
		element.operation = 1;
		req2.data.shareInfos.add(element);

		
		
		SetDeviceShare.Response resp2 = (SetDeviceShare.Response) m_client2.request(req2, 30000);

		if (resp2 == null) {
			logger.error("调用接口时发生未知发错");
			return new ReturnObject(false, "发生未知发错");
		}

		if (resp2.getCode() == HttpStatus.SC_OK) {
			if (resp2.getApiRetCode() == HsviewResponse.API_SUCCESS) {
				return new ReturnObject(true, "[" + resp2.getApiRetCode() + "] " + resp2.getApiRetDesc());
			} else {
				logger.warn("[" + resp2.getApiRetCode() + "] " + resp2.getApiRetDesc());
				return new ReturnObject(false, "[" + resp2.getApiRetCode() + "] " + resp2.getApiRetDesc());
			}
		} else {
			logger.error("[" + resp2.getApiRetCode() + "] " + resp2.getApiRetDesc());
			return new ReturnObject(false, "[" + resp2.getCode() + "] " + resp2.getDesc());
		}
	}

	@RequestMapping(value = "/unbindDevice", method = RequestMethod.POST, produces = MediaTypes.JSON_UTF_8)
	@ResponseBody
	public ReturnObject unbindDevice(@RequestBody UnbindDeviceRequestDto dto) {

		logger.debug("-------------unbindDevice data:" + dto);

		HsviewClient m_client = new HsviewClient();
		m_client.setHost(Config.host);
		m_client.setAuth(Config.devUser, Config.devPassword); // �û���// ����

		DeleteDeviceShare req = new DeleteDeviceShare();
		req.data.deviceId = dto.getDeviceId();
		req.data.channelId = "0";
		req.data.username = SecurityUtils.getCurrentSecurityUser().getUsername();

		DeleteDeviceShare.Response resp = (DeleteDeviceShare.Response) m_client.request(req, 30000);

		if (resp == null) {
			logger.error("调用DeleteDeviceShare接口时发生未知发错");
			return new ReturnObject(false, "发生未知发错");
		}

		logger.info("DeleteDeviceShare response data:" + resp.getBody());

		if (resp.getCode() == HttpStatus.SC_OK) {
			if (resp.getApiRetCode() == HsviewResponse.API_SUCCESS) {
				dhDeviceService.deleteDevice(dto.getDeviceId());
				return _realUnbindDevice(dto);
			} else {
				logger.warn("[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());
				return new ReturnObject(false, "[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());
			}
		} else {
			logger.error("[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());
			return new ReturnObject(false, "[" + resp.getCode() + "] " + resp.getDesc());
		}

	}

	private ReturnObject _realUnbindDevice(UnbindDeviceRequestDto dto) {
		logger.info("UnbindDevice data:" + dto);

		HsviewClient m_client2 = new HsviewClient();
		m_client2.setHost(Config.host);
		m_client2.setAuth(Config.devUser, Config.devPassword);

		UnbindDevice req2 = new UnbindDevice();
		req2.data.deviceId = dto.getDeviceId();
		req2.data.deleteCloudRecords = dto.isDeleteCloudRecords();

		UnbindDevice.Response resp2 = (UnbindDevice.Response) m_client2.request(req2, 30000);

		if (resp2 == null) {
			logger.error("调用UnbindDevice接口时发生未知发错");
			return new ReturnObject(false, "发生未知发错");
		}

		logger.info("UnbindDevice response data:" + resp2.getBody());

		if (resp2.getCode() == HttpStatus.SC_OK) {
			if (resp2.getApiRetCode() == HsviewResponse.API_SUCCESS) {
				return new ReturnObject(true, "[" + resp2.getApiRetCode() + "] " + resp2.getApiRetDesc());

			} else {
				logger.warn("[" + resp2.getApiRetCode() + "] " + resp2.getApiRetDesc());
				return new ReturnObject(false, "[" + resp2.getApiRetCode() + "] " + resp2.getApiRetDesc());
			}
		} else {
			logger.error("[" + resp2.getApiRetCode() + "] " + resp2.getApiRetDesc());
			return new ReturnObject(false, "[" + resp2.getCode() + "] " + resp2.getDesc());
		}

	}
	
	/**
	 * author 刘秀君 
	 * 用户手动设置用户名称
	 */
	@RequestMapping(value = "/updateDeviceName", method = RequestMethod.POST, produces = MediaTypes.JSON_UTF_8)
	@ResponseBody
	public ReturnObject updateDeviceName(@RequestBody UpdateDeviceRequestDto dto) {
		logger.info("-----------updateDeviceName data:" + dto);
		try {
			String deviceId = dto.getDeviceId();
			String deviceName = dto.getDeviceName();
			
			dhDeviceService.updateDeviceName(deviceId, deviceName);
		} catch (Exception e) {
			e.printStackTrace();
			logger.debug(e.getMessage());
			return new ReturnObject(false, "[deviceId] or [deviceName] does not matched");
		}
		return new ReturnObject(true, "");
	}
	
	/**
	 * author 王维平
	 * 设备分享-到视频广场、个人
	 */
	@RequestMapping(value = "/shareToDeviceSquare", method = RequestMethod.POST, produces = MediaTypes.JSON_UTF_8)
	@ResponseBody
	public ReturnObject shareToDeviceSquare(@RequestBody ShareDeviceRequestDto dto) {
		logger.debug("--------------shareToDeviceSquare data:" + dto);
		//该设备保存到设备分享表	
		try{
			dhDeviceShareService.shareDevice(dhDeviceService.findByDeviceId(dto.getDeviceId()), dto.getSharedType() , dto.getBeSharedTo());
			return new ReturnObject(true, "分享成功");
		}catch(Exception e){
			logger.error("设备分享出错");
			e.printStackTrace();
			return new ReturnObject(false, "分享失败：" + e.getMessage());
		}
	}
	
	/**
	 * author 王维平
	 * 取消设备分享
	 */
	@RequestMapping(value = "/cancelDeviceShared", method = RequestMethod.POST, produces = MediaTypes.JSON_UTF_8)
	@ResponseBody
	public ReturnObject cancelDeviceShared(@RequestBody ShareDeviceRequestDto dto) {
		logger.debug("-------------cancelDeviceShared data:" + dto);
		try{
			dhDeviceShareService.cancelDeviceShared(dto.getDeviceId());
			return new ReturnObject(true, "分享成功");
		}catch(Exception e){
			logger.error("取消设备分享出错");
			e.printStackTrace();
			return new ReturnObject(false, "分享失败：" + e.getMessage());
		}
	}
	
	/**
	 * author 王维平
	 * 获取视频广场的所有视频
	 */
	@RequestMapping(value = "/getDeviceSquare", method = RequestMethod.POST, produces = MediaTypes.JSON_UTF_8)
	@ResponseBody
	public ReturnObject getDeviceSquare() {
		try{
			List<GetDevicesResponseDto> result = new ArrayList<GetDevicesResponseDto>();
			List<DhDeviceShare> dhDeviceShares = dhDeviceShareService.getDeviceSquare();
			if (dhDeviceShares != null && dhDeviceShares.size() > 0) {
				for (DhDeviceShare share : dhDeviceShares) {
					result.add(new GetDevicesResponseDto(share.getDeviceId(), share.isOnline(), share.getDeviceModel(), share.getDeviceName(), dhDeviceChannelService.getChannelsByDeviceId(share.getDeviceId())));
				}
			}
			ReturnObject ro = new ReturnObject();
			ro.setSuccess(true);
			ro.setObj(result);
			return ro;
		}catch(Exception e) {
			logger.error("获取视频广场列表失败");
			e.printStackTrace();
			return new ReturnObject(false, "获取视频广场列表失败：" + e.getMessage());
		}
	}
	
	/**
	 * by Kevin Liu
	 * 获取指定设备Channels
	 * @param dto
	 * @return
	 */
	@RequestMapping(value = "/getDeviceChannels", method = RequestMethod.POST, produces = MediaTypes.JSON_UTF_8)
	public ReturnObject getDeviceChannels(@RequestBody GetDeviceChannelsRequestDto dto) {
		try {
			logger.info("GetDeviceChannels request data:" + mapper.writeValueAsString(dto));
		} catch (JsonProcessingException e) {
			logger.warn(e.getMessage());
		}
		
		HsviewClient m_client = new HsviewClient();
		m_client.setHost(Config.host);
		m_client.setAuth(Config.devUser, Config.devPassword); 
		
		GetDevices req = new GetDevices();
		GetDevices.Response resp = (GetDevices.Response) m_client.request(req, 30000);
		
		if (resp == null) {
			logger.error("调用GetDevices接口时发生未知发错");
			return new ReturnObject(false, "发生未知发错");
		}
		
		logger.info("GetDevices response data:" + resp.getBody());
		
		ReturnObject ro = new ReturnObject();
		
		
		if (resp.getCode() == HttpStatus.SC_OK) {
			if (resp.getApiRetCode() == HsviewResponse.API_SUCCESS) {
				
				GetDeviceChannelsResponseDto result = new GetDeviceChannelsResponseDto();
				
				for(GetDevices.ResponseData.DevicesElement element : resp.data.devices) {
					if(dto.getDeviceId().equals(element.deviceId)) {
						result.setDeviceId(dto.getDeviceId());
						result.setName(element.name);
						result.setBeSharedFrom(element.beSharedFrom);
						result.setBeSharedTo(element.beSharedTo);
						result.setDeviceModel(element.deviceModel);
						result.setOnline(element.online);
						for (GetDevices.ResponseData.DevicesElement.ChannelsElement channelElement : element.channels) {
							ChannelDto channelDto = new ChannelDto();
							channelDto.setChannelId(channelElement.channelId);
							channelDto.setChannelName(channelElement.channelName);
							channelDto.setChannelOnline(channelElement.channelOnline);
							channelDto.setChannelPicUrl(channelElement.channelPicUrl);
							
							result.getChannels().add(channelDto);
						}
						break;
					}
				}
				ro.setSuccess(true);
				ro.setObj(result);
			} else {
				ro.setSuccess(false);
				ro.setMsg("[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());
				logger.warn("[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());
			}
			
		} else {
			ro.setSuccess(false);
			ro.setMsg("[" + resp.getCode() + "] " + resp.getDesc());
			logger.error("[" + resp.getApiRetCode() + "] " + resp.getApiRetDesc());
		}
		
		return ro;
	}


}
